﻿using CoreWCF;
using SD.Infrastructure.DTOBase;
using SlamDunk.MES.AppService.Maps;
using SlamDunk.MES.Domain.Entities.AcquisitionContext;
using SlamDunk.MES.Domain.IRepositories;
using SlamDunk.MES.Domain.Mediators;
using SlamDunk.MES.IAppService.DTOs.Inputs;
using SlamDunk.MES.IAppService.DTOs.Outputs.AcquisitionContext;
using SlamDunk.MES.IAppService.DTOs.Outputs.DefinitionContext;
using SlamDunk.MES.IAppService.DTOs.Outputs.ExecutionContext;
using SlamDunk.MES.IAppService.DTOs.Outputs.PlanContext;
using SlamDunk.MES.IAppService.DTOs.Outputs.ResourceContext;
using SlamDunk.MES.IAppService.Interfaces;
using System;
using System.Collections.Generic;
using System.Linq;

namespace SlamDunk.MES.AppService.Implements
{
    /// <summary>
    /// 数据采集服务契约实现
    /// </summary>
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall, IncludeExceptionDetailInFaults = true)]
    public class AcquisitionContract : IAcquisitionContract
    {
        #region # 字段及构造器

        /// <summary>
        /// 仓储中介者
        /// </summary>
        private readonly RepositoryMediator _repMediator;

        /// <summary>
        /// 单元事务
        /// </summary>
        private readonly IUnitOfWorkMES _unitOfWork;

        /// <summary>
        /// 依赖注入构造器
        /// </summary>
        public AcquisitionContract(RepositoryMediator repMediator, IUnitOfWorkMES unitOfWork)
        {
            this._repMediator = repMediator;
            this._unitOfWork = unitOfWork;
        }

        #endregion


        //命令部分

        #region # 创建采集规则 —— void CreateAcquisitionRule(string ruleNo, string ruleName...
        /// <summary>
        /// 创建采集规则
        /// </summary>
        /// <param name="ruleNo">采集规则编号</param>
        /// <param name="ruleName">采集规则名称</param>
        /// <param name="processId">工艺Id</param>
        /// <param name="processSegmentId">工艺段Id</param>
        /// <param name="interval">采集间隔（单位：秒）</param>
        /// <param name="description">描述</param>
        /// <param name="ruleItemParams">采集规则项参数模型集</param>
        public void CreateAcquisitionRule(string ruleNo, string ruleName, Guid? processId, Guid? processSegmentId, int interval, string description, IEnumerable<AcquisitionRuleItemParam> ruleItemParams)
        {
            #region # 验证

            ruleItemParams = ruleItemParams?.ToArray() ?? Array.Empty<AcquisitionRuleItemParam>();
            if (!ruleItemParams.Any())
            {
                throw new ArgumentNullException(nameof(ruleItemParams), "采集规则项不可为空！");
            }
            if (processSegmentId.HasValue && this._repMediator.AcquisitionRuleRep.ExistsByProcessSegment(processSegmentId.Value))
            {
                throw new ArgumentOutOfRangeException(nameof(processSegmentId), "给定工艺段已存在采集规则！");
            }

            #endregion

            IEnumerable<AcquisitionRuleItem> ruleItems =
                from ruleItemParam in ruleItemParams
                select new AcquisitionRuleItem(ruleItemParam.variableNo, ruleItemParam.variableName, ruleItemParam.equipmentNo, ruleItemParam.sort, ruleItemParam.description);

            AcquisitionRule acquisitionRule = new AcquisitionRule(ruleNo, ruleName, processId, processSegmentId, interval, description);
            acquisitionRule.SetItems(ruleItems);

            this._unitOfWork.RegisterAdd(acquisitionRule);
            this._unitOfWork.Commit();
        }
        #endregion

        #region # 修改采集规则 —— void UpdateAcquisitionRule(Guid acquisitionRuleId, string ruleNo...
        /// <summary>
        /// 修改采集规则
        /// </summary>
        /// <param name="acquisitionRuleId">采集规则Id</param>
        /// <param name="ruleNo">采集规则编号</param>
        /// <param name="ruleName">采集规则名称</param>
        /// <param name="processId">工艺Id</param>
        /// <param name="processSegmentId">工艺段Id</param>
        /// <param name="interval">采集间隔（单位：秒）</param>
        /// <param name="description">描述</param>
        /// <param name="ruleItemParams">采集规则项参数模型集</param>
        public void UpdateAcquisitionRule(Guid acquisitionRuleId, string ruleNo, string ruleName, Guid? processId, Guid? processSegmentId, int interval, string description, IEnumerable<AcquisitionRuleItemParam> ruleItemParams)
        {
            #region # 验证

            ruleItemParams = ruleItemParams?.ToArray() ?? Array.Empty<AcquisitionRuleItemParam>();
            if (!ruleItemParams.Any())
            {
                throw new ArgumentNullException(nameof(ruleItemParams), "采集规则项不可为空！");
            }

            #endregion

            IEnumerable<AcquisitionRuleItem> ruleItems =
                from ruleItemParam in ruleItemParams
                select new AcquisitionRuleItem(ruleItemParam.variableNo, ruleItemParam.variableName, ruleItemParam.equipmentNo, ruleItemParam.sort, ruleItemParam.description);

            AcquisitionRule acquisitionRule = this._unitOfWork.Resolve<AcquisitionRule>(acquisitionRuleId);

            #region # 验证

            if (processSegmentId.HasValue &&
                processSegmentId.Value != acquisitionRule.ProcessSegmentId &&
                this._repMediator.AcquisitionRuleRep.ExistsByProcessSegment(processSegmentId.Value))
            {
                throw new ArgumentOutOfRangeException(nameof(processSegmentId), "给定工艺段已存在采集规则！");
            }

            #endregion

            acquisitionRule.UpdateInfo(ruleNo, ruleName, processId, processSegmentId, interval, description);
            acquisitionRule.SetItems(ruleItems);

            this._unitOfWork.RegisterSave(acquisitionRule);
            this._unitOfWork.Commit();
        }
        #endregion

        #region # 删除采集规则 —— void RemoveAcquisitionRule(Guid acquisitionRuleId)
        /// <summary>
        /// 删除采集规则
        /// </summary>
        /// <param name="acquisitionRuleId">采集规则Id</param>
        public void RemoveAcquisitionRule(Guid acquisitionRuleId)
        {
            this._unitOfWork.RegisterRemove<AcquisitionRule>(acquisitionRuleId);
            this._unitOfWork.Commit();
        }
        #endregion

        #region # 创建采集会话 —— Guid CreateAcquisitionSession(Guid acquisitionRuleId, Guid? processId...
        /// <summary>
        /// 创建采集会话
        /// </summary>
        /// <param name="acquisitionRuleId">采集规则Id</param>
        /// <param name="processId">工艺Id</param>
        /// <param name="processSegmentId">工艺段Id</param>
        /// <param name="executionPlanId">作业计划Id</param>
        /// <param name="workOrderId">工单Id</param>
        /// <returns>采集会话Id</returns>
        public Guid CreateAcquisitionSession(Guid acquisitionRuleId, Guid? processId, Guid? processSegmentId, Guid? executionPlanId, Guid? workOrderId)
        {
            AcquisitionRule acquisitionRule = this._repMediator.AcquisitionRuleRep.Single(acquisitionRuleId);
            AcquisitionSession acquisitionSession = new AcquisitionSession(acquisitionRule.Id, acquisitionRule.Interval, processId, processSegmentId, executionPlanId, workOrderId);

            this._unitOfWork.RegisterAdd(acquisitionSession);
            this._unitOfWork.Commit();

            return acquisitionSession.Id;
        }
        #endregion

        #region # 激活采集会话 —— void ActivateAcquisitionSession(Guid acquisitionSessionId)
        /// <summary>
        /// 激活采集会话
        /// </summary>
        /// <param name="acquisitionSessionId">采集会话Id</param>
        public void ActivateAcquisitionSession(Guid acquisitionSessionId)
        {
            AcquisitionSession acquisitionSession = this._unitOfWork.Resolve<AcquisitionSession>(acquisitionSessionId);
            acquisitionSession.Activate();

            this._unitOfWork.RegisterSave(acquisitionSession);
            this._unitOfWork.Commit();
        }
        #endregion

        #region # 关闭采集会话 —— void CloseAcquisitionSession(Guid acquisitionSessionId...
        /// <summary>
        /// 关闭采集会话
        /// </summary>
        /// <param name="acquisitionSessionId">采集会话Id</param>
        /// <param name="reason">关闭原因</param>
        public void CloseAcquisitionSession(Guid acquisitionSessionId, string reason)
        {
            AcquisitionSession acquisitionSession = this._unitOfWork.Resolve<AcquisitionSession>(acquisitionSessionId);
            acquisitionSession.Close(reason);

            this._unitOfWork.RegisterSave(acquisitionSession);
            this._unitOfWork.Commit();
        }
        #endregion

        #region # 追加采集记录 —— void AppendAcquisitionRecords(Guid acquisitionSessionId...
        /// <summary>
        /// 追加采集记录
        /// </summary>
        /// <param name="acquisitionSessionId">采集会话Id</param>
        /// <param name="recordParams">采集记录参数模型集</param>
        public void AppendAcquisitionRecords(Guid acquisitionSessionId, IEnumerable<AcquisitionRecordParam> recordParams)
        {
            #region # 验证

            recordParams = recordParams?.ToArray() ?? Array.Empty<AcquisitionRecordParam>();
            if (!recordParams.Any())
            {
                return;
            }

            #endregion

            AcquisitionSession acquisitionSession = this._unitOfWork.Resolve<AcquisitionSession>(acquisitionSessionId);
            foreach (AcquisitionRecordParam recordParam in recordParams)
            {
                AcquisitionRecord record = new AcquisitionRecord(recordParam.acquiredTime, recordParam.variableNo, recordParam.variableName, recordParam.value, recordParam.unit, recordParam.equipmentNo);
                acquisitionSession.AppendRecord(record);

            }

            this._unitOfWork.RegisterSave(acquisitionSession);
            this._unitOfWork.Commit();
        }
        #endregion


        //查询部分

        #region # 分页获取采集规则列表 —— PageModel<AcquisitionRuleInfo> GetAcquisitionRulesByPage(string...
        /// <summary>
        /// 分页获取采集规则列表
        /// </summary>
        /// <param name="keywords">关键字</param>
        /// <param name="processId">工艺Id</param>
        /// <param name="processSegmentId">工艺段Id</param>
        /// <param name="pageIndex">页码</param>
        /// <param name="pageSize">页容量</param>
        /// <returns>采集规则列表</returns>
        public PageModel<AcquisitionRuleInfo> GetAcquisitionRulesByPage(string keywords, Guid? processId, Guid? processSegmentId, int pageIndex, int pageSize)
        {
            ICollection<AcquisitionRule> acquisitionRules = this._repMediator.AcquisitionRuleRep.FindByPage(keywords, pageIndex, pageSize, out int rowCount, out int pageCount);

            IEnumerable<Guid> processIds = acquisitionRules.Where(x => x.ProcessId.HasValue).Select(x => x.ProcessId.Value);
            IEnumerable<Guid> processSegmentIds = acquisitionRules.Where(x => x.ProcessSegmentId.HasValue).Select(x => x.ProcessSegmentId.Value);
            IDictionary<Guid, ProcessInfo> processInfos = this._repMediator.ProcessRep.Find(processIds).ToDictionary(x => x.Key, x => x.Value.ToDTO(null, null, null));
            IDictionary<Guid, ProcessSegmentInfo> processSegmentInfos = this._repMediator.ProcessSegmentRep.Find(processSegmentIds).ToDictionary(x => x.Key, x => x.Value.ToDTO(null, null));

            IEnumerable<AcquisitionRuleInfo> acquisitionRuleInfos = acquisitionRules.Select(x => x.ToDTO(processInfos, processSegmentInfos));

            return new PageModel<AcquisitionRuleInfo>(acquisitionRuleInfos, pageIndex, pageSize, pageCount, rowCount);
        }
        #endregion

        #region # 是否存在工艺段相关采集规则 —— bool ExistsAcquisitionRuleByProcessSegment(Guid processSegmentId)
        /// <summary>
        /// 是否存在工艺段相关采集规则
        /// </summary>
        /// <param name="processSegmentId">工艺段Id</param>
        /// <returns>是否存在</returns>
        public bool ExistsAcquisitionRuleByProcessSegment(Guid processSegmentId)
        {
            return this._repMediator.AcquisitionRuleRep.ExistsByProcessSegment(processSegmentId);
        }
        #endregion

        #region # 获取采集规则项列表 —— IEnumerable<AcquisitionRuleItemInfo> GetAcquisitionRuleItems(...
        /// <summary>
        /// 获取采集规则项列表
        /// </summary>
        /// <param name="acquisitionRuleId">采集规则Id</param>
        /// <returns>采集规则项列表</returns>
        public IEnumerable<AcquisitionRuleItemInfo> GetAcquisitionRuleItems(Guid acquisitionRuleId)
        {
            ICollection<AcquisitionRuleItem> ruleItems = this._repMediator.AcquisitionRuleItemRep.Find(acquisitionRuleId);

            IEnumerable<string> equipmentNos = ruleItems.Where(x => !string.IsNullOrWhiteSpace(x.EquipmentNo)).Select(x => x.EquipmentNo);
            IDictionary<string, EquipmentInfo> equipmentInfos = this._repMediator.EquipmentRep.Find(equipmentNos).ToDictionary(x => x.Key, x => x.Value.ToDTO(null));

            IEnumerable<AcquisitionRuleItemInfo> ruleItemInfos = ruleItems.Select(x => x.ToDTO(equipmentInfos));

            return ruleItemInfos;
        }
        #endregion

        #region # 分页获取采集会话列表 —— PageModel<AcquisitionSessionInfo> GetAcquisitionSessionsByPage(...
        /// <summary>
        /// 分页获取采集会话列表
        /// </summary>
        /// <param name="acquisitionRuleId">采集规则Id</param>
        /// <param name="processId">工艺Id</param>
        /// <param name="processSegmentId">工艺段Id</param>
        /// <param name="executionPlanId">作业计划Id</param>
        /// <param name="workOrderId">工单Id</param>
        /// <param name="active">是否活动</param>
        /// <param name="startTime">开始时间</param>
        /// <param name="endTime">结束时间</param>
        /// <param name="pageIndex">页码</param>
        /// <param name="pageSize">页容量</param>
        /// <returns>采集会话列表</returns>
        public PageModel<AcquisitionSessionInfo> GetAcquisitionSessionsByPage(Guid? acquisitionRuleId, Guid? processId, Guid? processSegmentId, Guid? executionPlanId, Guid? workOrderId, bool? active, DateTime? startTime, DateTime? endTime, int pageIndex, int pageSize)
        {
            ICollection<AcquisitionSession> acquisitionSessions = this._repMediator.AcquisitionSessionRep.FindByPage(acquisitionRuleId, processId, processSegmentId, executionPlanId, workOrderId, active, startTime, endTime, pageIndex, pageSize, out int rowCount, out int pageCount);

            IEnumerable<Guid> processIds = acquisitionSessions.Where(x => x.ProcessId.HasValue).Select(x => x.ProcessId.Value);
            IEnumerable<Guid> processSegmentIds = acquisitionSessions.Where(x => x.ProcessSegmentId.HasValue).Select(x => x.ProcessSegmentId.Value);
            IEnumerable<Guid> executionPlanIds = acquisitionSessions.Where(x => x.ExecutionPlanId.HasValue).Select(x => x.ExecutionPlanId.Value);
            IEnumerable<Guid> workOrderIds = acquisitionSessions.Where(x => x.WorkOrderId.HasValue).Select(x => x.WorkOrderId.Value);
            IDictionary<Guid, ProcessInfo> processInfos = this._repMediator.ProcessRep.Find(processIds).ToDictionary(x => x.Key, x => x.Value.ToDTO(null, null, null));
            IDictionary<Guid, ProcessSegmentInfo> processSegmentInfos = this._repMediator.ProcessSegmentRep.Find(processSegmentIds).ToDictionary(x => x.Key, x => x.Value.ToDTO(null, null));
            IDictionary<Guid, ExecutionPlanInfo> executionPlanInfos = this._repMediator.ExecutionPlanRep.Find(executionPlanIds).ToDictionary(x => x.Key, x => x.Value.ToDTO(null, null, null, null, null));
            IDictionary<Guid, WorkOrderInfo> workOrderInfos = this._repMediator.WorkOrderRep.Find(workOrderIds).ToDictionary(x => x.Key, x => x.Value.ToDTO(null, null, null, null, null));

            IEnumerable<AcquisitionSessionInfo> acquisitionSessionInfos = acquisitionSessions.Select(x => x.ToDTO(processInfos, processSegmentInfos, executionPlanInfos, workOrderInfos));

            return new PageModel<AcquisitionSessionInfo>(acquisitionSessionInfos, pageIndex, pageSize, pageCount, rowCount);
        }
        #endregion

        #region # 获取采集记录列表 —— IEnumerable<AcquisitionRecordInfo> GetAcquisitionRecords(Guid...
        /// <summary>
        /// 获取采集记录列表
        /// </summary>
        /// <param name="acquisitionSessionId">采集会话Id</param>
        /// <returns>采集记录列表</returns>
        public IEnumerable<AcquisitionRecordInfo> GetAcquisitionRecords(Guid acquisitionSessionId)
        {
            ICollection<AcquisitionRecord> records = this._repMediator.AcquisitionRecordRep.Find(acquisitionSessionId);

            IEnumerable<string> equipmentNos = records.Where(x => !string.IsNullOrWhiteSpace(x.EquipmentNo)).Select(x => x.EquipmentNo);
            IDictionary<string, EquipmentInfo> equipmentInfos = this._repMediator.EquipmentRep.Find(equipmentNos).ToDictionary(x => x.Key, x => x.Value.ToDTO(null));

            IEnumerable<AcquisitionRecordInfo> recordInfos = records.Select(x => x.ToDTO(equipmentInfos));

            return recordInfos;
        }
        #endregion
    }
}
